Repository navigation
fix(codex): see a native draft before writing into it; restart into an empty 0.157 composer (#800, #1313) - #1319
Merged
Merged
Conversation
…n empty 0.157 composer (#800, #1313) Bumps codex-headless to 1ac3c50 (#53 base64 proxy chunks, #54 getComposerState). A normal delivery into a human's draft is refused as occupied instead of appending to it; a draft publishes composer-occupied and its clearing publishes ready; a restart request consents on Codex's own empty-composer reading, which the text check could never give on 0.157. Tests replay the recorded 0.157 bytes through a real CodexHeadless. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A draft longer than the package's composer bound read `unknown`, the screen check still passed, and a delivery pasted into the human's draft. Ready now needs a proof of empty (the package's reading or the old bare-marker text proof); text that nothing proves empty is refused at once as a human's to resolve, and readiness withdraws ready as provider-not-ready without latching occupied. Tests use steering's 13-row shape. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…two polls The plain screen can lag PTY bytes still being parsed, which is exactly when the cell reading says `unknown`; one stale bare-marker read consented and a normal delivery pasted into a draft the human had just started. The text proof now has to hold on two consecutive polls. Main merged in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Juliusolsson05
added a commit
that referenced
this pull request
Sep 26, 2026
…ntinue, #1319 fixes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ative draft; Ctrl+C clears it Review C: a Codex submit is one raw PTY write, so while composer-occupied, Enter in Agent Code's composer pasted the prompt after the native draft and Codex submitted both. Submit now refuses while occupied (every provider), keeping the draft, and Ctrl+C reaches the agent, since that is how 0.157 clears a draft. Review B: publication is pinned through the real screen listener, and the restart's final empty check has its own test. The orchestration hold and the nativeDraft tool text now mention a native draft. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Juliusolsson05
added a commit
that referenced
this pull request
Sep 26, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…trl+C keeps our draft A2: the text proof of an empty composer read the plain screen, which shows the previous paint while PTY bytes are still being parsed, and two polls do not prove the parser caught up. The write gate, readiness publication and the restart's final check now read the settled screen (codex-headless#55), null while anything is unparsed; null waits or refuses, never consents. B: Ctrl+C while the agent's composer is occupied clears the AGENT's draft only; it no longer deletes the follow-up typed in Agent Code. Pins the image-only occupied refusal too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Settled reads now also refuse inside an open synchronized update and after an unredrawn resize, and count a chunk before pty-data listeners run. Interim pointer; the final bump goes to #55's merge commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s provider-neutral A guard narrowed to provider === 'codex' survived every test. Claude also publishes composer-occupied and submits with a raw write, so it is pinned with a Claude pane. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y from the settled text proof Deleting the publication's text fallback passed every test. Pins that a pane with no shortcuts hint (package says unknown) publishes ready from a settled bare marker, and stays provider-not-ready while the settled read is null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ounds unknown is no longer 'today's behaviour': it never consents and publishes provider-not-ready. Records the settled screen, the pane's own Enter/Ctrl+C rules, the full test list, and the residuals (#1327). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…4d5ac) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
Review disposition (final head
|
Owner
Author
|
Verification addendum: round-2 reviewers A and B each did one focused verification pass at |
Juliusolsson05
added a commit
that referenced
this pull request
Sep 27, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1313. Refs #800 (not closed: its remaining case is #1327). Residual: #1327.
Plan:
docs/plans/2026-09-25-codex-composer-occupancy.md(first commit, kept current).Why
Evidence is the raw PTY recording of codex-cli 0.157.0 in codex-headless (
testing/fixtures/composer-0157/idle-draft-ctrlc.json).isCodexNativeComposerEmptycannot call the 0.157 empty composer empty. It shows a dim› Ask Codex to do anything, with a hint row under the status row. So every browser-pocket restart (requireEmptyNativeComposer) was refused.awaitReadyForPromptwas ready for any›row, so a delivery pasted after the human's draft and submitted both. Readiness latched once at startup, sonativeDraftstayedunknown.What merges
Package bump.
packages/codex-headlessgoesae0e935→6334d5ac, the merge of codex-headless#55. That includes #53, #54 and #55:getComposerState()returnsempty,draftedorunknown, from cell attributes and Codex's own hint row.getSettledScreen()returns the plain viewport only for a settled frame, andnullotherwise. Settled means no chunk is queued in the parser, no synchronized update is open, and Codex has painted since the last resize.The module is resolved from source, so no lockfile resync is needed.
One rule.
draftedis occupied. A proof of empty is ready. Anything else never consents and never latches occupied. A proof of empty is either the package'sempty, or a bare›above the status row read from the settled screen, nevergetScreen().Write gate:
draftedrefuses withretry-after-resolveand writes nothing.Restart: the final empty check applies the same proof on its own, even after readiness said ready.
Readiness publication:
draftedcomposer-occupiedreadyprovider-not-readynativeDraftreportsoccupied, and the pane says "draft in agent composer — clear it to send".Agent Code's composer while
composer-occupied, for every provider:Tool text: the orchestration hold text and the
nativeDraftdoc mention a native draft.Tests
codexSession.nativeComposer.test.ts(9 tests) replays the recorded bytes through a realCodexHeadless:composer-occupiedis published, thenreadyafter Ctrl+C.readyonly from a settled bare marker.Other suites:
codexSession.launchOrdering.test.ts: publication through the real screen listener.useComposerKeybinds.tab.renderer.test.tsx(11 tests): occupied Enter refuses for text, image-only, and a non-Codex provider; Ctrl+C passes and keeps our draft.Red baseline. These tests are red against main's application code with the new package: restart refused, draft delivered, no publication. On exact main they throw earlier, because the old package has no
snapshotComposerCells.Each new rule was mutation-checked, and every mutant listed in the review disposition is killed.
Verification
npx tsc -bis clean.workflows/control.systemneeds a builtpackages/workflow-mcp/dist, which this worktree lacks. It passes in the main checkout.claudeHistory.systempasses when run alone.b3971a7e(origin/maind15a9756merged in): quality-gate and minimum-node-fixture-gate pass. Codex suites + keybinds 142/142,npx tsc -bclean after the merge.Residuals
provider-not-ready. Needs a separate "unreadable draft" reason. Orchestration already refuses this case.Note on #1317
#1317 (the #53 bump alone) is merged. This PR's pointer contains it.
🤖 Generated with Claude Code